package main;

import java.awt.BasicStroke;
import java.awt.Button;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

public class HeroicShootUI extends ShootUI {
	public HeroicShootMouse myMouse;
	public Panel targetStats;
	
	public static enum choosingHeroes {FIRST, COUNTER, MULTIPLE, DONE, NONE};
	public choosingHeroes choosingHero;
	public int selectingArmy = 0;
	
	public Button callHeroicShoot;
	public Button skipHeroicShoot;
	
	public Button counterCall;
	public Button skipCounter;
	
	public boolean bothChoosing;
	public Button doneChoosing;
	
	public Button shootButton;
	public Button doneShooting;
	
	public Hero currentHero;
	public ArrayList<Hero> callingHeroes;
	public ArrayList<Unit> shootingUnits;
	
	public void beginPhase() {
		myUI.selectedUnit = null;
		myUI.targetedUnit = null;
		myUI.endPhase.setEnabled(false);
		
		currentHero = null;
		callingHeroes = new ArrayList<Hero>();
		shootingUnits = new ArrayList<Unit>();
		
		choosingHero = HeroicShootUI.choosingHeroes.NONE;
		
		if (!this.heroicShotPossible((myUI.game.priority+1)%2)) {
			this.endPhase();
			return;
		}
		
		
		bothChoosing = true;
		selectingArmy = (myUI.game.priority+1)%2;
		
		myMouse = new HeroicShootMouse();
		myMouse.myUI = myUI;
		myMouse.myShootUI = this;
		myUI.addMouseListener(myMouse);
		myUI.addMouseMotionListener(myMouse);
		
		targetStats = myUI.buildStatsPanel("Target", myUI.dim.width-200, myUI.dim.height-280);
		myUI.add(targetStats);
		
		
		callHeroicShoot = new Button("Call Heroic Shoot");
		callHeroicShoot.setBounds(myUI.dim.width-100,50,100,50);
		callHeroicShoot.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				callHeroicShoot.setVisible(false);
				skipHeroicShoot.setVisible(false);
				UI.messageLog.add(Game.armyTitles[selectingArmy] + ", select a hero to call the shot");
				choosingHero = HeroicShootUI.choosingHeroes.FIRST;
				myUI.repaint();
			}
		});
		myUI.add(callHeroicShoot);
		
		
		skipHeroicShoot = new Button("Skip Heroic Shoot");
		skipHeroicShoot.setBounds(myUI.dim.width-100,100,100,50);
		skipHeroicShoot.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				endPhase();
			}
		});
		myUI.add(skipHeroicShoot);
		
		
		counterCall = new Button("Counter call?");
		counterCall.setBounds(myUI.dim.width-100,50,100,50);
		counterCall.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				counterCall.setVisible(false);
				skipCounter.setVisible(false);
				UI.messageLog.add(Game.armyTitles[selectingArmy] + ", select a hero to counter the call");
				choosingHero = HeroicShootUI.choosingHeroes.COUNTER;
				myUI.repaint();
			}
		});
		myUI.add(counterCall);
		counterCall.setVisible(false);
		
		skipCounter = new Button("Skip counter");
		skipCounter.setBounds(myUI.dim.width-100, 100, 100, 50);
		skipCounter.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				counterCall.setVisible(false);
				skipCounter.setVisible(false);
				int newSelectingArmy = (selectingArmy+1)%2;
				// If the other guys can add more callers, let them
				if (heroicShotPossible(newSelectingArmy)) {
					selectingArmy = newSelectingArmy;
					UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call or select done");
					choosingHero = HeroicShootUI.choosingHeroes.MULTIPLE;
					bothChoosing = false;
					doneChoosing.setVisible(true);
				}
				
				// Otherwise, just be done
				else {
					UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " is out of heroes that can call a shot");
					choosingHero = HeroicShootUI.choosingHeroes.DONE;
					doneShooting.setVisible(true);
					shootButton.setVisible(true);
					advanceShooters();
				}
				myUI.repaint();
			}
		});
		myUI.add(skipCounter);
		skipCounter.setVisible(false);
		
		
		doneChoosing = new Button("Done choosing");
		doneChoosing.setBounds(myUI.dim.width-100, 50, 100, 50);
		doneChoosing.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int newSelectingArmy = (selectingArmy+1)%2;
				// If both were choosing, advance to other army and notify that both aren't anymore
				if (bothChoosing) {
					bothChoosing = false;
					selectingArmy = newSelectingArmy;
					// If we also don't have any more heroes to call, end it
					if (!heroicShotPossible(selectingArmy)){
						UI.messageLog.add(Game.armyTitles[selectingArmy] + " is out of heroes that can call a shot");
						choosingHero = HeroicShootUI.choosingHeroes.DONE;
						doneShooting.setVisible(true);
						shootButton.setVisible(true);
						advanceShooters();
					}
				}
				// Otherwise, we're done choosing for good and we can start shooting
				else {
					choosingHero = HeroicShootUI.choosingHeroes.DONE;
					doneShooting.setVisible(true);
					shootButton.setVisible(true);
					advanceShooters();
				}
				myUI.repaint();
			}
		});
		myUI.add(doneChoosing);
		doneChoosing.setVisible(false);
		
		shootButton = new Button("Shoot");
		shootButton.setName("Shoot");
		shootButton.setBounds(myUI.dim.width-100,50,100,50);
		shootButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(myUI.selectedUnit != null && myUI.targetedUnit != null
						&& shootingUnits.contains(myUI.selectedUnit)){
					setShooting(true);
					myUI.selectedUnit.shootAt(myUI.targetedUnit);
				}
				myUI.repaint();
			}
		});
		myUI.add(shootButton);
		shootButton.setVisible(false);
		
		doneShooting = new Button("Done Shooting");
		doneShooting.setBounds(myUI.dim.width-100,100,100,50);
		doneShooting.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				advanceShooters();
				myUI.repaint();
			}
		});
		myUI.add(doneShooting);
		doneShooting.setVisible(false);
		
		
		
		myUI.revalidate();
		myUI.repaint();
	}
	
	private boolean heroicShotPossible(int armyIndex) {
		for (Unit u : myUI.game.armies[armyIndex].units){
			if (u instanceof Hero && u.mightLeft > 0 && 
					u.battle == null && !callingHeroes.contains((Hero)u)
					&& !u.isTransfixed)
				return true;
		}
		return false;
	}
	
	
	public void addFirstCaller(Hero hero) {
		// Assumption is that the Heroic Shoot buttons are already hidden

		UI.messageLog.add(hero.toChoiceString() + " is calling a heroic shot!");
		// Add him to the calling heroes list
		callingHeroes.add(hero);
		
		// If we can counter call, enable the buttons and set choosingHero to none
		int newSelectingArmy = (this.selectingArmy+1)%2;
		if (this.heroicShotPossible(newSelectingArmy)) {
			this.selectingArmy = newSelectingArmy;
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose whether or not to counter the call");
			this.choosingHero = HeroicShootUI.choosingHeroes.NONE;
			this.counterCall.setVisible(true);
			this.skipCounter.setVisible(true);
		}
		// Otherwise, set to multiple if we have more options
		else if (this.heroicShotPossible(this.selectingArmy)) {
			UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " has no heroes that can counter call");
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call or select done");
			this.choosingHero = HeroicShootUI.choosingHeroes.MULTIPLE;
			this.bothChoosing = false;
			this.doneChoosing.setVisible(true);
		}
		
		// Otherwise, just be done
		else {
			UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " has no heroes that can counter call");
			UI.messageLog.add(Game.armyTitles[selectingArmy] + " is out of heroes that can call a shot");
			this.choosingHero = HeroicShootUI.choosingHeroes.DONE;
			this.doneShooting.setVisible(true);
			this.shootButton.setVisible(true);
			this.advanceShooters();
		}
		myUI.repaint();
	}

	public void addCounterCaller(Hero hero) {
		// Assumes counter buttons have been cleaned up
		
		UI.messageLog.add(hero.toChoiceString() + " is calling a heroic shot!");
		// Decide who gets to go first
		int firstSide = UI.rng.nextInt(2);
		
		UI.messageLog.add(Game.armyTitles[firstSide] + " has won the coinflip and will be shooting first");
		// Add him in depending on who's going to be going first
		if (firstSide == hero.armyIndex){
			this.callingHeroes.add(0, hero);
		}
		else {
			this.callingHeroes.add(hero);
		}
		
		// If the first side can continue, set them as the next to select in multiple
		if (this.heroicShotPossible(firstSide)) {
			this.selectingArmy = firstSide;
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call or select done");
			this.choosingHero = HeroicShootUI.choosingHeroes.MULTIPLE;
			this.doneChoosing.setVisible(true);
		}
		// Otherwise, set to second side if they have more options
		else if (this.heroicShotPossible((firstSide+1)%2)) {
			UI.messageLog.add(Game.armyTitles[firstSide] + " is out of heroes that can call a shot");
			this.selectingArmy = (firstSide+1)%2;
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a shot or select done");
			this.choosingHero = HeroicShootUI.choosingHeroes.MULTIPLE;
			this.bothChoosing = false;
			this.doneChoosing.setVisible(true);
		}
		// Otherwise, just be done
		else {
			UI.messageLog.add("Both sides are out of heroes that can call a shot");
			this.choosingHero = HeroicShootUI.choosingHeroes.DONE;
			this.doneShooting.setVisible(true);
			this.shootButton.setVisible(true);
			this.advanceShooters();
		}
		myUI.repaint();
	}

	public void addCallingHero(Hero hero) {
		hero.useMight(1);
		this.callingHeroes.add(hero);
		UI.messageLog.add(hero.toChoiceString() + " is calling a heroic shot!");
		if (this.bothChoosing) {
			int newSelectingArmy = (this.selectingArmy+1)%2;
			if (this.heroicShotPossible(newSelectingArmy)) {
				this.selectingArmy = newSelectingArmy;
				UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a shot or select done");
			}
			else {
				UI.messageLog.add(Game.armyTitles[newSelectingArmy] + " is out of heroes that can call a shot");
				UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a shot or select done");
				this.bothChoosing = false;
				// Not both choosing anymore, continue with this army
			}
		}
		if (!this.heroicShotPossible(this.selectingArmy)) {
			// No more heroes can call, move on to actually shooting
			this.choosingHero = HeroicShootUI.choosingHeroes.DONE;
			this.doneChoosing.setVisible(false);
			this.doneShooting.setVisible(true);
			this.shootButton.setVisible(true);
			this.advanceShooters();
		}
		else {
			UI.messageLog.add(Game.armyTitles[selectingArmy] + ", choose another hero to call a shot or select done");
		}
	}
	
	public void advanceShooters() {
		myUI.selectedUnit = null;
		myUI.targetedUnit = null;
		if (this.callingHeroes.size() == 0) {
			// Move on to normal shoot phase
			this.endPhase();
		}
		else {
			Hero nextHero = this.callingHeroes.get(0);
			this.callingHeroes.remove(0);
			this.currentHero = nextHero;
			if (nextHero.wounds <= 0) {
				// He died before getting to call his shot
				this.advanceShooters();
			}
			else {
				// We have an actual caller, update the list of units allowed to shoot
				this.shootingUnits = new ArrayList<Unit>();
				for (Unit u : nextHero.army.units){
					if (Utils.inchDist(nextHero, u) <= 6 && u.battle == null)
						this.shootingUnits.add(u);
				}
			}
		}
	}

	public void setShooting(boolean shooting) {
		this.shootButton.setEnabled(!shooting);
		this.doneShooting.setEnabled(!shooting);
	}
	
	public void endPhase() {
		// Transition to normal Shoot Phase
		// Clean up shoot stuff
		myUI.removeMouseListener(myMouse);
		myUI.removeMouseMotionListener(myMouse);
		
		// Clean up various Butons and Panels
		if (targetStats != null) {
			myUI.remove(targetStats);
			myUI.remove(callHeroicShoot);
			myUI.remove(skipHeroicShoot);
			myUI.remove(shootButton);
			myUI.remove(counterCall);
			myUI.remove(skipCounter);
			myUI.remove(doneChoosing);
			myUI.remove(doneShooting);
		}
		
		if (choosingHero != HeroicShootUI.choosingHeroes.NONE)
			UI.messageLog.add("Finished Heroic Shots, moving to normal Shoot Phase");
		
		myUI.endPhase.setEnabled(true);
		myUI.selectedUnit = null;
		myUI.targetedUnit = null;
		
		// Create a ShootUI and set it to be the new phase
		ShootUI shootUI = new ShootUI();
		shootUI.myUI = myUI;
		myUI.phaseUI = shootUI;
		myUI.phaseUI.beginPhase();
		myUI.repaint();
	}
	
	public void paint(Graphics bufferG) {
    	if (myUI.targetedUnit != null && myUI.targetedUnit.getWounds() > 0){
    		bufferG.setColor(Color.red);
    		bufferG.drawOval(myUI.targetedUnit.x-(myUI.targetedUnit.pixelRadius+1)-myUI.boardOffsetX, 
    							myUI.targetedUnit.y-(myUI.targetedUnit.pixelRadius+1)-myUI.boardOffsetY, 
    							2*(myUI.targetedUnit.pixelRadius+1), 2*(myUI.targetedUnit.pixelRadius+1));
    		bufferG.setColor(Color.black);
    	}
    	// Draw ovals for units able to shoot
    	((Graphics2D)bufferG).setStroke(new BasicStroke(2));
		bufferG.setColor(Color.ORANGE);
    	for (Unit u : shootingUnits) {
    		if (u.shootRange > 0
    				&& u.moveLeft >= u.move * u.moveNeededToShoot
    				&& u.battle == null
    				&& !u.hasShot
    				&& !u.layingDown) {
    			bufferG.drawOval(u.x-(u.pixelRadius+2)-myUI.boardOffsetX, u.y-(u.pixelRadius+2)-myUI.boardOffsetY, 
    								2*(u.pixelRadius+2), 2*(u.pixelRadius+2));
    		}
    	}
    	bufferG.setColor(Color.BLACK);
		((Graphics2D)bufferG).setStroke(new BasicStroke());
		
		updateTargetPanel();
	}

}
